﻿#region

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Vin.Extension.Framework.Adapter;
using Vin.Extension.Framework.Dto;
using Vin.Extension.Framework.Models;
using Vin.Extension.JwtBearer.Attributes;
using Vin.Extension.JwtBearer.Extension;
using Vin.Tool.AspNetCore.Extension;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Core.AssertCategory;

#endregion

namespace Vin.Extension.Framework.Aop;

public class VinAuthorizeAttribute(string? permission = null) : VinJwtAuthorizeAttribute
{
    public string? Permission { get; set; } = permission;

    /// <summary>
    /// 分隔符
    /// </summary>
    public string Separator { get; set; } = ",";

    /// <summary>
    /// 授权适配器
    /// </summary>
    private List<IVinAuthorizeAdapter>? _vinAuthorizeAdapters;

    public override void OnAuthorization(AuthorizationFilterContext context)
    {
        // 如果有授权适配器，校验
        _vinAuthorizeAdapters = VinApp.GetServicesByHttpContext<IVinAuthorizeAdapter>().ToList();
        _vinAuthorizeAdapters?.ForEach(m => m.BeginAuthorize(this));

        base.OnAuthorization(context);
        if (context.Result != null) return;

        #region 获取授权信息

        var model = VinTokenModelTool.GetTokenModel(TokenPrefix);
        if (model == null || model.LoginSuccess == false)
        {
            context.Unauthorized();
            return;
        }

        #endregion
        
        #region 适配器校验

        if (_vinAuthorizeAdapters != null)
        {
            if (_vinAuthorizeAdapters.Any(adapter => !adapter.Authorize(model)))
            {
                context.Unauthorized();
                return;
            }
        }

        #endregion
        
        #region 内部校验

        // 判断是否超级管理员
        if (model.IsSuperAdmin == true) return;

        // 判断是否登录成功
        if (model.LoginSuccess == false)
        {
            context.Unauthorized();
            return;
        }

        // 判断必填项
        if (!CheckRequired(model))
        {
            context.Unauthorized();
            return;
        }

        #endregion

        #region 权限校验

        // 判断权限
        if (model.Permissions is not null)
        {
            var permissions = Permission?.Split(Separator);
            if (permissions is { Length: > 0 })
            {
                // 取交集
                if (permissions.Any(permission => !model.Permissions!.Contains(permission)))
                {
                    context.Forbidden();
                    return;
                }
            }
        }

        #endregion

        // 结束授权适配器
        _vinAuthorizeAdapters?.ForEach(m => m.EndAuthorize());
    }

    /// <summary>
    /// 检查必填项
    /// </summary>
    /// <param name="model"></param>
    private bool CheckRequired(VinTokenModel model)
    {
        var requiredFields = model.GetType().GetFields().Where(m => m.GetCustomAttributes(typeof(RequiredAttribute),
            true).Length > 0);
        var requiredProperties = model.GetType().GetProperties().Where(m => m
            .GetCustomAttributes(typeof(RequiredAttribute),
                true).Length > 0);
        if (requiredFields.Any(field => field.GetValue(model).IsNull())) return false;

        if (requiredProperties.Any(property => property.GetValue(model).IsNull())) return false;

        return true;
    }
}